{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7e42bce7-0d67-4707-87bf-d05028384674",
   "metadata": {},
   "source": [
    "## 数据下载与加载："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29c9dd23-fec0-4554-8c4d-8978c2b05fcb",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "\n",
    "# 数据预处理\n",
    "transform = transforms.Compose(\n",
    "    [transforms.ToTensor(),\n",
    "     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n",
    "\n",
    "# 下载并加载训练集\n",
    "trainset = torchvision.datasets.CIFAR10(root='./data', train=True,\n",
    "                                        download=True, transform=transform)\n",
    "trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,\n",
    "                                          shuffle=True, num_workers=2)\n",
    "\n",
    "# 下载并加载测试集\n",
    "testset = torchvision.datasets.CIFAR10(root='./data', train=False,\n",
    "                                       download=True, transform=transform)\n",
    "testloader = torch.utils.data.DataLoader(testset, batch_size=4,\n",
    "                                         shuffle=False, num_workers=2)\n",
    "\n",
    "classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e76d556-1fb7-413a-96d7-eadc8a524c6f",
   "metadata": {},
   "source": [
    "## 定义CNN类："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a46221e2-196c-4063-bb71-26bbfeb99d40",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(3, 6, 5)\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "        self.conv2 = nn.Conv2d(6, 16, 5)\n",
    "        self.fc1 = nn.Linear(16 * 5 * 5, 120)\n",
    "        self.fc2 = nn.Linear(120, 84)\n",
    "        self.fc3 = nn.Linear(84, 10)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.pool(F.relu(self.conv1(x)))\n",
    "        x = self.pool(F.relu(self.conv2(x)))\n",
    "        x = x.view(-1, 16 * 5 * 5)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = F.relu(self.fc2(x))\n",
    "        x = self.fc3(x)\n",
    "        return x\n",
    "\n",
    "net = Net()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f5cf197-3693-4985-8159-55622237fdcf",
   "metadata": {},
   "source": [
    "## 定义损失函数和优化器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5576ba8e-14a9-498d-92f2-9d0b7843e9e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.optim as optim\n",
    "\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.Adam(net.parameters(), lr=0.001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5863c77e-3bb1-4bb3-a3cf-5d7f908fac17",
   "metadata": {},
   "source": [
    "## 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7ce3317-8904-4562-8c9f-4442bfdb00a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 记录每个epoch的损失\n",
    "epoch_losses = []\n",
    " \n",
    "for epoch in range(2):  # 迭代2个epoch\n",
    "    running_loss = 0.0\n",
    "    for i, data in enumerate(trainloader, 0):\n",
    "        # 获取输入\n",
    "        inputs, labels = data\n",
    " \n",
    "        # 零梯度\n",
    "        optimizer.zero_grad()\n",
    " \n",
    "        # 前向传播 + 反向传播 + 优化\n",
    "        outputs = net(inputs)\n",
    "        loss = criterion(outputs, labels)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    " \n",
    "        # 累加损失\n",
    "        running_loss += loss.item()\n",
    " \n",
    "    # 计算并记录每个epoch的平均损失\n",
    "    epoch_loss = running_loss / len(trainloader)\n",
    "    epoch_losses.append(epoch_loss)\n",
    "    print(f'Epoch [{epoch+1}/2], Loss: {epoch_loss:.4f}')\n",
    " \n",
    "print('Finished Training')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46a80afd-4b13-498b-bd34-a90567d7bf74",
   "metadata": {},
   "source": [
    "## 在测试集上测试模型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2871790-7491-4392-b285-98995db1c9f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 测试网络\n",
    "correct = 0\n",
    "total = 0\n",
    "with torch.no_grad():\n",
    "    for data in testloader:\n",
    "        images, labels = data\n",
    "        outputs = net(images)\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        total += labels.size(0)\n",
    "        correct += (predicted == labels).sum().item()\n",
    " \n",
    "print('Accuracy of the network on the 10000 test images: %d %%' % (\n",
    "    100 * correct / total))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b8da694-5964-4b5b-9d99-9bad23d4e3d2",
   "metadata": {},
   "source": [
    "## 绘制学习曲线"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d98367ce-24ed-4917-8438-14ee9fe0e803",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 绘制学习曲线\n",
    "import matplotlib.pyplot as plt\n",
    "plt.figure(figsize=(8, 4))\n",
    "plt.plot(range(1, len(epoch_losses) + 1), epoch_losses, label='Training Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.title('Learning Curve')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.savefig('图1', dpi=300)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
